热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开辟|黑体字_数据结构之顺序表

篇首语:本文由编程笔记#小编为大家整理,主要介绍了数据结构之顺序表相关的知识,希望对你有一定的参考价值。 目录 顺序表概念顺序表实现静态顺序表的结构定义动态顺序表的结构定义顺序表初始化顺序表打印检查

篇首语:本文由编程笔记#小编为大家整理,主要介绍了数据结构之顺序表相关的知识,希望对你有一定的参考价值。



目录


  • 顺序表概念
  • 顺序表实现
    • 静态顺序表的结构定义
    • 动态顺序表的结构定义
      • 顺序表初始化
      • 顺序表打印
      • 检查空间进行扩容
      • 顺序表尾插
      • 顺序表尾删
      • 顺序表头插
      • 顺序表头删
      • 顺序表查找
      • 在任意位置插入
      • 在任意位置删除
      • 顺序表销毁


  • 头文件
  • 源文件


顺序表概念

线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素,这种表示也称作线性表的顺序存储结构或顺序映像。通常,称这种存储结构的线性表为顺序表(Sequential List)。其特点是,逻辑上相邻的数据元素,其物理次序也是相邻的
线性表的顺序存储结构是一种随机存取的存储结构,一般情况下采用数组存储。
解释下黑体字:假设现在已经实现了每个元素类型为int型的顺序表,并且插入了1、2、3、4、5五个元素。

64位平台下一个整型(int)占4个字节,元素1的后面是2,2的后面是3,我们可以清晰的看到元素1的地址后面就是2的地址,2的地址后面就是3的地址,每两个地址之间就相差它们自身占用空间字节数。
就像这样:


顺序表实现

静态顺序表的结构定义

#define N 500
typedef int SQDataType;
typedef struct SeqList

SQDataType a[N];
int size;
SLT;

静态顺序表在实际中是非常不适用的,空间给小了不够用,给多了可能会浪费,所以最好定义成动态的。


动态顺序表的结构定义

typedef int SQDatatype;
typedef struct SeqList

SQDatatype* a; //指向动态开辟数组的指针
int size; //有效数据的个数
int capacity; //容量空间大小
SLT;

typedef的作用是可以为某一类型自定义名称。编译器会将带有typedef关键字的SQDatatype解释成一个类型的标识符,即int型。这样做的好处是当顺序表中的存储元素是char类型时,只需要将int改为char即可,提高了程序的灵活性。
接下来定义一个结构体,结构体当中有三个成员。
第一个结构体成员为一个指向数组的指针,因为顺序表一般情况下采用数组存储。
第二个结构体成员变量size为数组中有效数据的个数。
假设数组动态开辟了4个整型空间,先插入1,2两个元素,此时有效数据2个,size = 2。

再插入3,4两个元素。

这时会发现我们再想插入数据时数组就越界了&#xff0c;空间不够了&#xff0c;所以需要第三个变量capacity&#xff0c;用来表示容量空间的大小。当有效数据个数size <容量capacity时&#xff0c;随便插入数据&#xff0c;因为数组还有空间&#xff1b;当size &#61;&#61; capacity时说明空间满了&#xff0c;再想插入数据需要扩容。


顺序表初始化

void SeqListInit(SLT* psl)

assert(psl); //psl不可能为NULL&#xff0c;对其进行断言
psl->a &#61; NULL;
psl->size &#61; psl->capacity &#61; 0;

将指针a赋值为NULL&#xff0c;有效数据个数size和容量capacity都赋值为0即可。
为什么函数参数是结构体指针呢&#xff1f;
先看一个简单的例子&#xff1a;

void Swap1(int x, int y)

int temp &#61; x;
x &#61; y;
y &#61; temp;

int main(void)

int a &#61; 10; //变量a
int b &#61; 20; //变量b
Swap1(a, b); //Swap()函数将两个数字交换
printf("a &#61; %d, b &#61; %d\\n", a, b);
return 0;


可以看到打印在屏幕上的结果&#xff0c;两个变量的值并没有交换。

调试发现形参x和y确实交换了&#xff0c;但是a和b的值没有变化&#xff0c;为什么呢&#xff1f;

void Swap2(int* x, int* y)

int temp &#61; *x;
*x &#61; *y;
*y &#61; temp;

int main(void)

int a &#61; 10;
int b &#61; 20;
Swap2(&a, &b);
printf("a &#61; %d, b &#61; %d\\n", a, b);
return 0;


这样a和b的值才会交换。
因为形参只是实参的一份临时拷贝&#xff0c;可以比较一下两次变量的地址。
这是Swap1()函数实参和形参的地址&#xff1a;

可以清晰的看到实参a&#xff0c;b与形参x&#xff0c;y使用的不是同一空间。
这是Swap2()函数实参和形参的地址&#xff1a;

发现实参a&#xff0c;b和形参x&#xff0c;y所用的是同一块空间&#xff0c;所以解引用取到x和y的值并且交换&#xff0c;自然也就交换了a和b的值。
上面改变了两个整型的值&#xff0c;需要传地址参数&#xff0c;结构体也一样&#xff0c;想改变结构体中的内容需要传递结构体的地址&#xff0c;用一个结构体指针接收。
断言
ANSI C实现了一个assert宏&#xff0c;当它被执行时&#xff0c;这个宏对表达式参数进行测试。如果它的值为假(零)&#xff0c;它就向标准错误打印一条诊断信息并终止程序。
这条信息的格式是由编译器定义的&#xff0c;它将包含这个表达式和源文件的名字以及断言所在的行号。如果表达式为真(非零)&#xff0c;将不会打印任何东西&#xff0c;程序继续执行。
初始化函数参数为结构体指针&#xff0c;指向结构体地址&#xff0c;这个地址不可能为空&#xff0c;所以可以对函数参数psl进行断言&#xff0c;如果psl为NULL&#xff0c;就会出现下面的结果&#xff1a;


顺序表打印

void SeqListPrint(SLT* psl)

assert(psl);
for (int i &#61; 0; i < psl->size; &#43;&#43;i)

printf("%d ", psl->a[i]);

printf("\\n");

用一个for循环输出数组中每一个有效数据。


检查空间进行扩容

void CheckCapacity(SLT* psl)

assert(psl);
if (psl->size &#61;&#61; psl->capacity)

size_t newCapacity &#61; psl->capacity &#61;&#61; 0 ? 4 : psl->capacity * 2;
SQDatatype* temp &#61; (SQDatatype*)realloc(psl->a, sizeof(SQDatatype) * newCapacity);
if (temp &#61;&#61; NULL) //如果temp为NULL说明开辟空间失败

printf("realloc fail");
exit(-1); //退出程序

psl->a &#61; temp;
psl->capacity &#61; newCapacity;


有效数据个数size和容量capacity相等需要扩容&#xff0c;如果容量capacity等于0&#xff0c;为其开辟4个整型空间&#xff0c;否则容量变为原来的二倍。
将新空间赋值给a&#xff0c;新容量赋值给capacity。


顺序表尾插

void SeqListPushBack(SLT* psl, SQDatatype x)

assert(psl);
CheckCapacity(psl); //检查是否需要扩容
psl->a[psl->size] &#61; x;
psl->size&#43;&#43;; //有效数据个数加一

要在顺序表尾部进行插入操作&#xff0c;插入元素下标的值和顺序表有效数据个数的值是相等的。

此时有效数据size为2&#xff0c;在2后面尾插个3&#xff0c;那么3的下标就是2&#xff0c;就是size的值。所以psl->a[psl->size] &#61; x&#xff0c;插入完成后有效数据个数变为3个&#xff0c;让size的值加1。


顺序表尾删

void SeqListPopBack(SLT* psl)

assert(psl);
assert(psl->size > 0);
psl->size--;

顺序表有元素的时候才可以进行删除操作&#xff0c;所以对顺序表的有效数据个数进行断言。如果顺序表中有元素&#xff0c;让有效数据个数减一即可。


顺序表头插

void SeqListPushFront(SLT* psl, SQDatatype x)

assert(psl);
CheckCapacity(psl); //检查是否需要扩容
for (int i &#61; psl->size; i > 0; --i)

psl->a[i] &#61; psl->a[i - 1];

psl->a[0] &#61; x; //将元素插入数组第一个位置
psl->size&#43;&#43;; //有效数据个数加一

假设顺序表有1、2、3、4四个元素&#xff0c;此时头插一个x的值为6。

此时size &#61;&#61; capacity&#xff0c;需要扩容。
扩容后&#xff1a;

将数组中的每个元素从最后一个开始赋值个后面一个。
即a[4] &#61; a[3]&#xff0c;a[3] &#61; a[2]











……


直至跳出循环。
循环结束后&#xff1a;

将数组下标为0的位置赋值为6&#xff0c;此时size &#61; 5&#xff0c;capacity &#61; 8。


顺序表头删

void SeqListPopFront(SLT* psl)

assert(psl); //psl不可能为NULL&#xff0c;对其进行断言
assert(psl->size > 0); //存在有效数据才进行删除
for (int i &#61; 0; i < psl->size - 1; &#43;&#43;i)

psl->a[i] &#61; psl->a[i &#43; 1];

psl->size--; //有效数据个数减一

从数组下标为1的元素开始&#xff0c;每个元素都赋值给前一个元素位置&#xff0c;让有效数据个数减一。


顺序表查找

查找顺序表中是否存在某一元素&#xff0c;若存在返回该元素下标&#xff0c;否则返回-1。

int SeqListFind(SLT* psl, SQDatatype x)

assert(psl); //psl不可能为NULL&#xff0c;对其进行断言
for (int i &#61; 0; i < psl->size; &#43;&#43;i)

if (x &#61;&#61; psl->a[i])
return i;

return -1;


在任意位置插入

void SeqListInsert(SLT* psl, size_t pos, SQDatatype x)

assert(psl);
assert(pos >&#61; 0 && pos <&#61; psl->size); //对插入位置pos取值进行断言
CheckCapacity(psl);
for (int i &#61; psl->size; i > pos; --i)

psl->a[i] &#61; psl->a[i - 1];

psl->a[pos] &#61; x; //将x赋值给下标为pos位置
psl->size&#43;&#43;; //有效数据个数加一

假设要在下标为pos的位置插入一个元素&#xff0c;pos的值一定在0和有效数据个数之间&#xff0c;即pos的取值范围[0&#xff0c;size]&#xff0c;pos值为0即头插&#xff0c;pos值为size即尾插。
将pos及其后面的元素向后挪动一位&#xff0c;将要插入的数据x赋值给下标为pos的位置。最后让有效数据的个数加一。


在任意位置删除

void SeqListErase(SLT* psl, size_t pos)

assert(psl); //对psl进行断言
assert(pos >&#61; 0 && pos < psl->size); //对pos取值进行断言
for (int i &#61; pos; i < psl->size - 1; &#43;&#43;i)

psl->a[i] &#61; psl->a[i &#43; 1];

psl->size--; //有效数据个数减一

想在任意位置删除时&#xff0c;pos的取值在[0&#xff0c;size)之间&#xff0c;因为数组最后一个元素的下标为size-1&#xff0c;假如删除size位置&#xff0c;数组越界了&#xff0c;所以这里是开区间。
让pos后面的位置都向前挪动一位&#xff0c;最后让有效数据的个数减一。


顺序表销毁

void SeqListDestory(SLT* psl)

assert(psl);
if (psl->a)

free(psl->a);
psl->a &#61; NULL;

psl->size &#61; psl->capacity &#61; 0;

将数组指针置空&#xff0c;并且将有效数据个数size和容量capacity也置空。


头文件

#pragma once
#include
#include
#include
typedef int SQDatatype;
typedef struct SeqList

SQDatatype* a;
int size; //有效数据的个数
int capacity; //容量
SLT;
//初始化
void SeqListInit(SLT* psl);
//销毁
void SeqListDestory(SLT* psl);
//打印
void SeqListPrint(SLT* psl);
//扩容
void CheckCapacity(SLT* psl);
//尾插
void SeqListPushBack(SLT* psl, SQDatatype x);
//尾删
void SeqListPopBack(SLT* psl);
//头插
void SeqListPushFront(SLT* psl, SQDatatype x);
//头删
void SeqListPopFront(SLT* psl);
//查找
int SeqListFind(SLT* psl, SQDatatype x);
//任意位置插入
void SeqListInsert(SLT* psl, size_t pos, SQDatatype x);
//任意位置删除
void SeqListErase(SLT* psl, size_t pos);

源文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void SeqListInit(SLT* psl) //初始化

assert(psl);
psl->a &#61; NULL;
psl->size &#61; psl->capacity &#61; 0;

void SeqListDestory(SLT* psl) //销毁

assert(psl);
if (psl->a)

free(psl->a);
psl->a &#61; NULL;

psl->size &#61; psl->capacity &#61; 0;

void SeqListPrint(SLT* psl) //打印

assert(psl);
for (int i &#61; 0; i < psl->size; &#43;&#43;i)

printf("%d ", psl->a[i]);

printf("\\n");

void CheckCapacity(SLT* psl) //检查空间进行扩容

assert(psl);
if (psl->size &#61;&#61; psl->capacity)

size_t newCapacity &#61; psl->capacity &#61;&#61; 0 ? 4 : psl->capacity * 2;
SQDatatype* temp &#61; (SQDatatype*)realloc(psl->a, sizeof(SQDatatype) * newCapacity);
if (temp &#61;&#61; NULL)

printf("realloc fail");
exit(-1);

psl->a &#61; temp;
psl->capacity &#61; newCapacity;


void SeqListPushBack(SLT* psl, SQDatatype x) //尾插

assert(psl);
CheckCapacity(psl);
psl->a[psl->size] &#61; x;
psl->size&#43;&#43;;

void SeqListPopBack(SLT* psl) //尾删

assert(psl);
assert(psl->size > 0);
psl->size--;

void SeqListPushFront(SLT* psl, SQDatatype x) //头插

assert(psl);
CheckCapacity(psl);
for (int i &#61; psl->size; i > 0; --i)

psl->a[i] &#61; psl->a[i - 1];

psl->a[0] &#61; x;
psl->size&#43;&#43;;

void SeqListPopFront(SLT* psl) //头删

assert(psl);
assert(psl->size > 0);
for (int i &#61; 0; i < psl->size - 1; &#43;&#43;i)

psl->a[i] &#61; psl->a[i &#43; 1];

psl->size--;

int SeqListFind(SLT* psl, SQDatatype x) //查找

assert(psl);
for (int i &#61; 0; i < psl->size; &#43;&#43;i)

if (x &#61;&#61; psl->a[i])
return i;

return -1;

void SeqListInsert(SLT* psl, size_t pos, SQDatatype x) //pos位置插入

assert(psl);
assert(pos >&#61; 0 && pos <&#61; psl->size);
CheckCapacity(psl);
for (int i &#61; psl->size; i > pos; --i)

psl->a[i] &#61; psl->a[i - 1];

psl->a[pos] &#61; x;
psl->size&#43;&#43;;

void SeqListErase(SLT* psl, size_t pos) //pos位置删除

assert(psl);
assert(pos >&#61; 0 && pos < psl->size);
for (int i &#61; pos; i < psl->size - 1; &#43;&#43;i)

psl->a[i] &#61; psl->a[i &#43; 1];

psl->size--;


推荐阅读
  • 本文详细介绍了如何通过修改Lua源码或使用动态链接库(DLL)的方式实现Lua与C++之间的高级交互,包括如何编译Lua源码、添加自定义API以及在C++中加载和调用Lua脚本。 ... [详细]
  • 本文介绍如何利用QFileSystemModel进行目录的浏览、创建及删除操作,并提供了一个简单的对话框界面实现。 ... [详细]
  • 寒武纪C++实习面试经验分享
    本文详细介绍了C++中的一些关键知识点,包括继承方式、虚继承、多态性以及引用与指针的使用场景。通过具体实例和代码示例,帮助读者更好地理解和应用这些概念。 ... [详细]
  • 本次竞赛包含三个编程题目,旨在考察参赛者对数学逻辑及时间处理的能力。题目涉及筛选特定条件下的数字、Unix时间戳转换以及数列中元素关系的分析。 ... [详细]
  • 本文介绍了如何在C++中使用new关键字动态创建一维和二维数组,并详细解释了常见的错误及其解决方案。 ... [详细]
  • 针对上一期关于 Windows 8 的问题,我们正在积极解决。本文提供 IE6,7,8 三个版本的单文件版下载,适用于 Windows Vista/7 系统,支持 x86 和 x64 架构。欢迎大家下载并分享。 ... [详细]
  • 请看|差别_Android 6.0 运行时权限处理解析
    请看|差别_Android 6.0 运行时权限处理解析 ... [详细]
  • C#反射reflection
    C#shanzm目录简介引入1.新建类库2.类库的使用3.反射反射实例1反射实例2反射实例3简介反射(reflection)是什么?在《精通C#》中是这么说的“反射就是一个运行库发 ... [详细]
  • 【UOJ】#37. 【清华集训2014】主旋律
    题解一道,神奇的题我们考虑正难则反,我们求去掉这些边后有多少图不是强连通的怎么求呢,不是强连通的图缩点后一定是一个DAG,并 ... [详细]
  • Java Set集合源码深度解析
    本文将深入探讨Java集合框架中的Set接口及其主要实现类HashSet、LinkedHashSet和TreeSet的源码实现,帮助读者理解这些集合类的工作原理及应用场景。 ... [详细]
  • 本文介绍了几个使用C++语言实现的递归算法案例,包括计算数组和、数组倒置、打印数字三角形以及解决经典的汉诺塔问题。 ... [详细]
  • 本文详细介绍了如何使用归并排序对链表进行排序,与数组的归并排序在逻辑上非常相似,但实现细节有所不同。 ... [详细]
  • 近期,公司在构建新的交易系统时遇到了一个常见的问题——金额存储。由于涉及资金的操作需要高度的准确性,使用float类型进行金额计算可能会导致不可预见的误差。本文将深入探讨这一问题,并提供解决方案。 ... [详细]
  • ExtJS项目高效打包与部署指南
    本文详细介绍了如何使用Sencha Cmd工具对ExtJS项目进行高效打包及部署,包括测试打包、检查依赖项以及生产环境下的打包方法。 ... [详细]
  • 本文介绍了如何使用Objective-C语言遍历指定文件夹,并根据文件扩展名来判断文件类型的方法。代码示例中通过创建一个文件管理器实例,利用目录枚举器遍历文件夹中的所有项,筛选出特定类型的文件。 ... [详细]
author-avatar
北辰孤星123
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有